/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.compiler; import java.util.*; import org.openide.util.enum.*; /** Graph of objects that is build over one Compilable object. * * @author Jaroslav Tulach */ final class Graph extends Object { /** vertexes indexed by Compilables (Compilable, Vertex) * @associates Vertex*/ private HashMap vertex = new HashMap (31); /** list with all levels */ private List levels; /** Creates new Graph. * Stores all dependencies into Vertexes so later changes to * deps are ignored. This constructor should be invoked under * Compilable.MUTEX.writeAccess so nobody can change the * dependencies when the constructor is executing. */ public Graph (final Compilable c) { Enumeration en = compilables (c); while (en.hasMoreElements ()) { Compilable com = (Compilable)en.nextElement (); Vertex v = (Vertex)vertex.get (com); if (v == null) { v = new Vertex (); vertex.put (com, v); } v.add (com); } addDeps (); } /** Test whether the graph is up-to-date * @return true if it is */ public boolean isUpToDate () { Iterator it = vertex.values ().iterator (); while (it.hasNext ()) { Vertex v = (Vertex)it.next (); if (!v.isUpToDate ()) { return false; } } return true; } /** Getter for levels in the graph. * @return List[Set[Compiler]] * @exception CyclicDependencyException if cycle has been detected */ public synchronized List getLevels () throws DependencyException { if (levels != null) { return levels; } List cycle = depth (); if (cycle == null) { // ok, levels computed return levels; } ListIterator it = cycle.listIterator (); while (it.hasNext ()) { Vertex v = (Vertex)it.next (); // first object it.set (v.compilables.iterator ().next ()); } Compilable[] arr = new Compilable[cycle.size ()]; cycle.toArray (arr); throw new DependencyException (arr); } /** Adds dependencies for all vertexes */ private void addDeps () { Iterator it = vertex.values ().iterator (); while (it.hasNext ()) { Vertex v = (Vertex)it.next (); addDeps (v); } } /** Adds dependencies for given vertex. * @param v vertex */ private void addDeps (Vertex v) { Iterator it = v.compilables.iterator (); while (it.hasNext ()) { Compilable c = (Compilable)it.next (); Iterator di = c.dependsOn ().iterator (); while (di.hasNext ()) { Compilable dc = (Compilable)di.next (); Vertex dv = (Vertex)vertex.get (dc); // also all compilers in compilable v depends on dv addCompilerDep (null, c.compilers (), dv); } addCompilerDep (v, c.compilers (), null); } } /** Adds dependency of compilers to a vertex. * @param compOwner vertex that should depend on all of the compilers * @param col collection of compilers * @param v vertex to depend on */ private void addCompilerDep (Vertex compOwner, Collection col, Vertex v) { Iterator it = col.iterator (); while (it.hasNext ()) { Compiler c = (Compiler)it.next (); Vertex cv = (Vertex)vertex.get (c); if (v != null) { cv.addDep (v); } if (compOwner != null && compOwner != cv) { // compOwner depends on each compiler except // special case when the owner and compiler are the // same objects compOwner.addDep (cv); } } } /** Assignes depth to vertexes in the graph. * @return null if it succeeds or List of Vertex objects that * form a cycle */ private List depth () { Iterator it = vertex.values ().iterator (); int max = -1; while (it.hasNext ()) { Vertex v = (Vertex)it.next (); if (v.depth > 0) { continue; } List cycle = computeDepth (v); if (cycle != null) { return cycle; } if (v.depth > max) { max = v.depth; } } // put into levels Set[] arr = new Set [max]; it = vertex.values ().iterator (); while (it.hasNext ()) { Vertex v = (Vertex)it.next (); int indx = v.depth - 1; if (arr[indx] == null) { arr[indx] = new HashSet (17); } addCompilersFrom (arr[indx], v.compilables); } levels = Arrays.asList (arr); return null; } /** Takes array of Compilables takes all Compilers from it * and add them into the first collection * @param compilers to add to * @param compilables to take from */ private static void addCompilersFrom ( Collection compilers, Collection compilables ) { Iterator it = compilables.iterator (); while (it.hasNext ()) { Object o = it.next (); if (o instanceof Compiler) { compilers.add (o); } } } /** Goes thru all of the vertexes and indexes them. * @param v the vertex to start at * @return the list of Vertex in cycle or null */ private static LinkedList computeDepth (Vertex v) { if (v.dependsOn == null) { v.depth = 1; return null; } if (v.depth == -1) { // cycle LinkedList ll = new LinkedList (); ll.add (v); return ll; } // to signal that we began processing v.depth = -1; int max = -1; Iterator it = v.dependsOn.iterator (); while (it.hasNext ()) { Vertex child = (Vertex)it.next (); LinkedList ll = computeDepth (child); if (ll != null) { if (ll.size () == 1 || ll.getFirst () != ll.getLast ()) { // we are still in the cycle // otherwise only get from the recursion ll.add (v); } return ll; } if (child.depth > max) { max = child.depth; } } if (max == -1 || v.anyCompiler () != null) { v.depth = max + 1; } else { v.depth = max; } return null; } /** Enumeration of all compilables accessible from the one. * @param c the compilable * @return enum of Compilable */ private static Enumeration compilables (Compilable c) { QueueEnumeration en = new QueueEnumeration () { private IdSet set = new IdSet (); public void process (Object o) { Compilable comp = (Compilable)o; set.add (comp); LinkedList ll = new LinkedList (comp.compilers ()); ll.addAll (comp.dependsOn ()); ll.removeAll (set); put (ll.toArray ()); } }; en.put (c); return en; } /** One vertex in the graph. Contains list of all compilers that * are equal and collection of other vertexes it depends on. */ private final static class Vertex extends Object { /** all compilers that are equal * @associates Compilable*/ public Collection compilables = new IdSet (); /** vertexes this depend on * @associates Vertex*/ public Collection dependsOn; /** depth in the graph */ public int depth; private static int count; private int cnt = ++count; /** debug */ public String toString () { StringBuffer sb = new StringBuffer (); sb.append ("Vertex "); // NOI18N sb.append (cnt); sb.append (" ("); // NOI18N sb.append (compilables); sb.append (", "); // NOI18N if (dependsOn == null) { sb.append ("null, "); // NOI18N } else { sb.append ("{"); // NOI18N Iterator it = dependsOn.iterator(); Vertex v = (Vertex)it.next (); sb.append (v.cnt); while (it.hasNext()) { sb.append (", "); // NOI18N Vertex vx = (Vertex)it.next (); sb.append (vx.cnt); } sb.append ("}, "); // NOI18N } sb.append (depth); sb.append (")"); // NOI18N return sb.toString (); } public void add (Compilable c) { compilables.add (c); } public void addDep (Vertex v) { if (dependsOn == null) { dependsOn = new IdSet (); } dependsOn.add (v); } public Compiler anyCompiler () { Iterator it = compilables.iterator (); while (it.hasNext ()) { Object o = it.next (); if (o instanceof Compiler) { return (Compiler)o; } } return null; } public boolean isUpToDate () { Iterator it = compilables.iterator (); while (it.hasNext ()) { Object o = it.next (); if (o instanceof Compiler && !((Compiler)o).isUpToDate ()) { return false; } } return true; } } } /* * Log * 3 Gandalf 1.2 1/13/00 Ian Formanek NOI18N * 2 Gandalf 1.1 1/13/00 Ales Novak System.out.println * removed * 1 Gandalf 1.0 12/23/99 Jaroslav Tulach * $ */